﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace tabtool
{
    class CodeGen
    {
        public static void MakeCppFile(List<TableMeta> metalist, string codepath)
        {
            string hfile = codepath + "tableconfig.h";
            using (FileStream fs = new FileStream(hfile, FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                {
                    sw.WriteLine("//THIS FILE IS GENERATED BY tabtool, DO NOT EDIT IT!");
                    sw.WriteLine("//GENERATE TIME [{0}]", System.DateTime.Now.ToString());
                    sw.WriteLine("#pragma once");
                    sw.WriteLine("# include \"tabletool/myconfig.h\"");
                    sw.WriteLine("# include \"tabletool/singleton.h\"");
                    sw.WriteLine("# include \"tabletool/readtablefield.h\"");
                    sw.WriteLine("# include \"tablestruct.h\"");
                    sw.WriteLine();
                    sw.WriteLine();
                    sw.WriteLine("bool LoadTableConfig();");
                    sw.WriteLine();

                    foreach (var meta in metalist)
                    {
                        sw.WriteLine();
                        sw.WriteLine("struct {0} {{", meta.GetItemName());
                        foreach(var field in meta.Fields)
                        {
                            sw.WriteLine("  {0} {1};", field.GetCppTypeName(), field.fieldName);
                        }
                        sw.WriteLine("};");
                        sw.WriteLine();
                        sw.WriteLine("class {0}:public IConfigTable<{1}>{{", meta.GetClassName(), meta.GetItemName());
                        sw.WriteLine("public:");
                        sw.WriteLine("    virtual bool Load();");
                        sw.WriteLine();
                        sw.WriteLine("    string GetTableFile()");
                        sw.WriteLine("    {");
                        sw.WriteLine("        string f = WORK_DIR;");
                        sw.WriteLine("        f = f + \"{0}.txt\";", meta.TableName);
                        sw.WriteLine("        return f;");
                        sw.WriteLine("    }");
                        sw.WriteLine();
                        sw.WriteLine("};");
                        sw.WriteLine();
                    }

                }
            }

            string cppfile = codepath + "tableconfig.cpp";
            using (FileStream fs = new FileStream(cppfile, FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                {
                    sw.WriteLine("//THIS FILE IS GENERATED BY tabtool, DO NOT EDIT IT!");
                    sw.WriteLine("//GENERATE TIME [{0}]", System.DateTime.Now.ToString());
                    sw.WriteLine("#include \"tableconfig.h\"");
                    sw.WriteLine();
                    sw.WriteLine("bool LoadTableConfig()");
                    sw.WriteLine("{");
                    sw.WriteLine("    stConfigScope scope;");
                    foreach (var meta in metalist)
                    {
                        sw.WriteLine("    if(false == Singleton<{0}>::Instance()->Load())", meta.GetClassName());
                        sw.WriteLine("    {");
                        sw.WriteLine("        ErrorLog(\"加载配置%s出错\",Singleton<{0}>::Instance()->GetTableFile().c_str() );", meta.GetClassName());
                        sw.WriteLine("        return false;");
                        sw.WriteLine("    }");
                    }
                    sw.WriteLine("    return true;");
                    sw.WriteLine("}");
                    sw.WriteLine();

                    foreach (var meta in metalist)
                    {
                        sw.WriteLine("bool {0}::Load()", meta.GetClassName());
                        sw.WriteLine("{");
                        sw.WriteLine("	ReadTableFile reader;");
                        sw.WriteLine("	reader.Initialize();");
                        sw.WriteLine();
                        sw.WriteLine("	if (!reader.Init(GetTableFile().c_str()))");
                        sw.WriteLine("		return false;");
                        sw.WriteLine();
                        sw.WriteLine("	DataReader dr;");
                        sw.WriteLine("	int iRows = reader.GetRowCount();");
                        sw.WriteLine("	int iCols = reader.GetColCount();");
                        sw.WriteLine();
                        sw.WriteLine("	for (int i = 1; i < iRows; ++i)");
                        sw.WriteLine("	{");
                        sw.WriteLine("		{0} item;", meta.GetItemName());
                        foreach (var field in meta.Fields)
                        {
                            switch (field.fieldType)
                            {
                                case TableFieldType.IntField:
                                    sw.WriteLine("		item.{0} = atoi(reader.GetValue(i, \"{0}\"));", field.fieldName);
                                    break;
                                case TableFieldType.FloatField:
                                    sw.WriteLine("		item.{0} = atof(reader.GetValue(i, \"{0}\"));", field.fieldName);
                                    break;
                                case TableFieldType.StringField:
                                    sw.WriteLine("		item.{0} = (reader.GetValue(i, \"{0}\"));", field.fieldName);
                                    break;
                                case TableFieldType.IntList:
                                    sw.WriteLine("		item.{0} = dr.GetIntList(reader.GetValue(i, \"{0}\"));", field.fieldName);
                                    break;
                                case TableFieldType.FloatList:
                                    sw.WriteLine("		item.{0} = dr.GetFloatList(reader.GetValue(i, \"{0}\"));", field.fieldName);
                                    break;
                                case TableFieldType.StringList:
                                    sw.WriteLine("      item.{0} = dr.GetStringList(reader.GetValue(i, \"{0}\"));", field.fieldName);
                                    break;
                                case TableFieldType.StructField:
                                    sw.WriteLine("      item.{0} = dr.GetObject<{1}>(reader.GetValue(i, \"{0}\"));", field.fieldName, field.GetCppTypeName());
                                    break;
                                case TableFieldType.StructList:
                                    sw.WriteLine("      item.{0} = dr.GetObjectList<{1}>(reader.GetValue(i, \"{0}\"));", field.fieldName, field.GetTypeNameOfStructList());
                                    break;
                            }
                        }
                        sw.WriteLine("		m_Items[item.id] = item;");//必须有一个id
                        sw.WriteLine("	}");
                        sw.WriteLine();
                        sw.WriteLine("	return true;");
                        sw.WriteLine("}");
                    }
                    ///////////////////

                }
            }
        }
        public static void MakeCppFileTbs(List<TableMeta> metalist, string codepath)
        {
            string hfile = codepath + "tablestruct.h";
            using (FileStream fs = new FileStream(hfile, FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                {
                    sw.WriteLine("//THIS FILE IS GENERATED BY tabtool, DO NOT EDIT IT!");
                    sw.WriteLine("//GENERATE TIME [{0}]", System.DateTime.Now.ToString());
                    sw.WriteLine("#pragma once");
                    sw.WriteLine("#include \"tabletool/readtablefield.h\"");
                    sw.WriteLine("#include \"tabletool/myconfig.h\"");
                    sw.WriteLine();

                    foreach (var meta in metalist)
                    {
                        sw.WriteLine();
                        sw.WriteLine("struct {0} : public ITableObject<{0}>", meta.TableName);
                        sw.WriteLine("{");
                        foreach (var field in meta.Fields)
                        {
                            sw.WriteLine("	{0} {1};", field.GetCppTypeName(), field.fieldName);
                        }
                        sw.WriteLine();
                        sw.WriteLine("	virtual bool FromString(string s)");
                        sw.WriteLine("	{");
                        sw.WriteLine("		DataReader dr;");
                        sw.WriteLine("		vector<string> vs = dr.GetStringList(s,',');");
                        sw.WriteLine("		if (vs.size() != {0})", meta.Fields.Count());
                        sw.WriteLine("		{");
                        sw.WriteLine("			ErrorLog(\"{0}字段配置错误\");", meta.TableName);
                        sw.WriteLine("			return false;");
                        sw.WriteLine("		}");
                        for (int i = 0; i < meta.Fields.Count(); i++)
                        {
                            var field = meta.Fields[i];
                            switch (field.fieldType)
                            {
                                case TableFieldType.IntField:
                                    sw.WriteLine("		{0} = stoi(vs[{1}]);", field.fieldName, i);
                                    break;
                                case TableFieldType.FloatField:
                                    sw.WriteLine("		{0} = stof(vs[{1}]);", field.fieldName, i);
                                    break;
                                case TableFieldType.StringField:
                                    sw.WriteLine("		{0} = (vs[{1}]);", field.fieldName, i);
                                    break;
                                default:
                                    Console.WriteLine("{0}.{1}字段类型错误，只能是int float string！", meta.TableName, field.fieldName);
                                    break;
                            }
                        }
                        sw.WriteLine("		return true;");
                        sw.WriteLine("	}");
                        sw.WriteLine("};");
                        sw.WriteLine();
                    }
                    ////////////////////////
                }
            }
        }

        public static void MakeCsharpFileTbs(List<TableMeta> metalist, string codepath)
        {
            string hfile = codepath + "TableStruct.cs";
            using (FileStream fs = new FileStream(hfile, FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                {
                    sw.WriteLine("//THIS FILE IS GENERATED BY tabtool, DO NOT EDIT IT!");
                    sw.WriteLine("//GENERATE TIME [{0}]", System.DateTime.Now.ToString());
                    sw.WriteLine();
                    sw.WriteLine("namespace tabtool");
                    sw.WriteLine("{");
                    foreach (var meta in metalist)
                    {
                        sw.WriteLine("  public class {0} : ITableObject", meta.TableName);
                        sw.WriteLine("  {");
                        foreach (var field in meta.Fields)
                        {
                            sw.WriteLine("      {0} {1};", field.GetCsharpTypeName(), field.fieldName);
                        }
                        sw.WriteLine("      public bool FromString(string s)");
                        sw.WriteLine("      {");
                        sw.WriteLine("          DataReader dr = new DataReader();");
                        sw.WriteLine();
                        sw.WriteLine("          var vs = s.Split(',');");
                        sw.WriteLine("          if (vs.Length != 2)");
                        sw.WriteLine("          {");
                        sw.WriteLine("              return false;");
                        sw.WriteLine("          }");
                        sw.WriteLine();
                        for (int i = 0; i < meta.Fields.Count(); i++)
                        {
                            var field = meta.Fields[i];
                            switch (field.fieldType)
                            {
                                case TableFieldType.IntField:
                                    sw.WriteLine("		{0} = dr.GetInt(vs[{1}]);", field.fieldName, i);
                                    break;
                                case TableFieldType.FloatField:
                                    sw.WriteLine("		{0} = dr.GetFloat(vs[{1}]);", field.fieldName, i);
                                    break;
                                case TableFieldType.StringField:
                                    sw.WriteLine("		{0} = vs[{1}];", field.fieldName, i);
                                    break;
                                default:
                                    Console.WriteLine("{0}.{1}字段类型错误，只能是int float string！", meta.TableName, field.fieldName);
                                    break;
                            }
                        }

                        sw.WriteLine("          return true;");
                        sw.WriteLine("      }");
                        sw.WriteLine("  };");
                        sw.WriteLine();
                    }
                    sw.WriteLine("}");

                    ////////////////////////
                }
            }

        }

        public static void MakeCsharpFile(List<TableMeta> metalist, string codepath)
        {
            string csfile = codepath + "TableConfig.cs";
            using (FileStream fs = new FileStream(csfile, FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
                {
                    sw.WriteLine("//THIS FILE IS GENERATED BY tabtool, DO NOT EDIT IT!");
                    sw.WriteLine("//GENERATE TIME [{0}]", System.DateTime.Now.ToString());
                    sw.WriteLine();
                    sw.WriteLine("using System.Collections;");
                    sw.WriteLine("using System.Collections.Generic;");
                    sw.WriteLine("using System.Data;");
                    sw.WriteLine();
                    sw.WriteLine("namespace tabtool");
                    sw.WriteLine("{");
                    foreach (var meta in metalist)
                    {
                        sw.WriteLine();
                        sw.WriteLine("    public class {0}", meta.GetItemName());
                        sw.WriteLine("    {");
                        foreach (var field in meta.Fields)
                        {
                            sw.WriteLine("        public {0} {1};", field.GetCsharpTypeName(), field.fieldName);
                        }
                        sw.WriteLine("    }");
                        sw.WriteLine();
                        sw.WriteLine("    public class {0} : TableManager<{1}, {0}>", meta.GetClassName(),meta.GetItemName());
                        sw.WriteLine("    {");
                        sw.WriteLine("        public override bool Load()");
                        sw.WriteLine("        {");
                        sw.WriteLine("            TableReader tr = new TableReader();");
                        sw.WriteLine("            DataReader dr = new DataReader();");
                        sw.WriteLine("            DataTable dt = tr.ReadFile(MyConfig.WorkDir+\"{0}.txt\");",meta.TableName);
                        sw.WriteLine();
                        sw.WriteLine("            foreach(DataRow row in dt.Rows)");
                        sw.WriteLine("            {");
                        sw.WriteLine("                var item = new {0}();", meta.GetItemName());

                        foreach (var field in meta.Fields)
                        {
                            switch (field.fieldType)
                            {
                                case TableFieldType.IntField:
                                    sw.WriteLine("                  item.{0} = dr.GetInt(row[\"{0}\"].ToString());", field.fieldName);
                                    break;
                                case TableFieldType.FloatField:
                                    sw.WriteLine("                  item.{0} = dr.GetFloat(row[\"{0}\"].ToString());", field.fieldName);
                                    break;
                                case TableFieldType.StringField:
                                    sw.WriteLine("                  item.{0} = (row[\"{0}\"].ToString());", field.fieldName);
                                    break;
                                case TableFieldType.IntList:
                                    sw.WriteLine("                  item.{0} = dr.GetIntList(row[\"{0}\"].ToString());", field.fieldName);
                                    break;
                                case TableFieldType.FloatList:
                                    sw.WriteLine("                  item.{0} = dr.GetFloatList(row[\"{0}\"].ToString());", field.fieldName);
                                    break;
                                case TableFieldType.StringList:
                                    sw.WriteLine("                  item.{0} = dr.GetStringList(row[\"{0}\"].ToString());", field.fieldName);
                                    break;
                                case TableFieldType.StructField:
                                    sw.WriteLine("                  item.{0} = dr.GetObject<{1}>(row[\"{0}\"].ToString());", field.fieldName, field.GetCsharpTypeName());
                                    break;
                                case TableFieldType.StructList:
                                    sw.WriteLine("                  item.{0} = dr.GetObjectList<{1}>(row[\"{0}\"].ToString());", field.fieldName, field.GetTypeNameOfStructList());
                                    break;
                            }
                        }
                        sw.WriteLine("                  m_Items[item.id] = item;");//必须有一个id
                        sw.WriteLine("            }");
                        sw.WriteLine("            return true;");
                        sw.WriteLine("        }");
                        sw.WriteLine("    }");
                        sw.WriteLine();
                    }

                    sw.WriteLine("    public class TableConfig : SingletonTable<TableConfig>");
                    sw.WriteLine("    {");
                    sw.WriteLine("        public bool LoadTableConfig()");
                    sw.WriteLine("        {");

                    foreach (var meta in metalist)
                    {
                        sw.WriteLine("            if (!{0}.Instance.Load()) return false;", meta.GetClassName());
                    }
                    sw.WriteLine("            return true;");
                    sw.WriteLine("        }");
                    sw.WriteLine("    }");

                    sw.WriteLine("}");
                    ///////////////////

                }
            }

        }
    }
}
